﻿using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace ModbusCase.Lib
{
    /// <summary>
    /// ModbusTCP协议封装
    /// </summary>
    public class ModbusTCP
    {
        private Socket _socket;
        private static readonly object lockObj = new object();

        public ModbusTCP(Socket socket)
        {
            _socket = socket;
        }

        #region 功能码0x01 0x02
        /// <summary>
        /// 功能码0x01 0x02
        /// </summary>
        /// <param name="funcCode">功能码。只支持0x01,0x02</param>
        /// <param name="startAddress">起始地址</param>
        /// <param name="count">读取数量</param>
        /// <returns>bool数组</returns>
        public bool[] ReadBools(FuncCode funcCode, ushort startAddress, ushort count)
        {
            if (funcCode != FuncCode.ReadCoils && funcCode != FuncCode.ReadDiscreteInputs)
            {
                throw new Exception("该方法只支持功能码0x01,0x02");
            }

            // 1.发送请求(send)
            // 2.获取响应数据(receive)
            // 3.分析返回结果。返回bool[]
            // 3.1 校验
            // 3.2 如果通过,取出数据并转换为bool[]
            lock (lockObj)
            {
                #region 1.发送请求
                // 发送的bytes
                List<byte> sendBytes = GetReadBytes(funcCode, startAddress, count);

                _socket.Send(sendBytes.ToArray());
                #endregion

                #region 2.获取响应数据

                // 报文返回的有9个字节是固定的即：读取的个数/8(返回的字节数) + 9(固定字节)
                int readCount = (int)Math.Ceiling(count * 1.0 / 8) + 9; // 读取字节的个数
                List<byte> receiveBytes = GetReceiveBytes(readCount);
                #endregion

                #region 3.分析返回结果。返回bool[]
                //3.1 校验
                ExceptionCheck(sendBytes, receiveBytes);

                // 3.2 如果通过校验,取出数据并转换为bool[]
                List<byte> dataBytes = receiveBytes.ToList().GetRange(9, readCount - 9);
                // 假设返回：05 00
                // 05= 0000 0101 
                // 00= 0000 0000
                bool[] tempBool = new bool[dataBytes.Count * 8]; // 临时变量
                for (int i = 0; i < dataBytes.Count; i++)
                {
                    for (int j = 0; j < 8; j++)
                    {
                        // i=0;j=0;
                        //  0000 0101
                        //& 0000 0001
                        //------------
                        //  0000 0001
                        // tempBool[0] = true;

                        // i=0;j=1;
                        //  0000 0101
                        //& 0000 0010
                        //------------
                        //  0000 0000
                        // tempBool[1] = false;

                        // i=0;j=2;
                        //  0000 0101
                        //& 0000 0100
                        //------------
                        //  0000 0100
                        // tempBool[2] = true;
                        tempBool[i * 8 + j] = (dataBytes[i] & (1 << j)) != 0;  // 通过位运算判断每一位是否为1
                    }
                }

                bool[] result = new bool[count]; // 最终结果
                Array.Copy(tempBool, result, count);

                return result;
                #endregion
            }
        }
        #endregion

        #region 读取保持寄存器(16位) 功能码0x03,0x04
        /// <summary>
        /// 读取保持寄存器(16位) 功能码0x03,0x04
        /// </summary>
        /// <param name="funcCode">功能码。只支持0x03,0x04</param>
        /// <param name="startAddress">起始地址</param>
        /// <param name="count">要读的数字个数(寄存器的个数)</param>
        /// <returns>数字数组</returns>
        public short[] ReadReg16(FuncCode funcCode, ushort startAddress, ushort count)
        {
            if (funcCode != FuncCode.ReadHoldingRegisters && funcCode != FuncCode.ReadInputRegisters)
            {
                throw new Exception("该方法只支持功能码0x03,0x04");
            }

            // 1.发送请求
            // 2.获取响应数据
            // 3.分析返回结果。返回short[]
            // 3.1 校验
            // 3.2 如果通过,取出数据并转换为short[]

            lock (lockObj)
            {
                #region 1.发送请求
                // 发送的bytes
                List<byte> sendBytes = GetReadBytes(funcCode, startAddress, count);

                _socket.Send(sendBytes.ToArray());
                #endregion

                #region 2.获取响应数据
                // 报文返回的有9个字节是固定的即：读取的数字的个数 * 2(一个寄存器2个字节) + 9(固定字节)
                int readCount = count * 2 + 9; // 读取字节的个数 

                List<byte> receiveBytes = GetReceiveBytes(readCount);
                #endregion

                #region 3.分析返回结果。返回short[]
                //3.1 校验
                ExceptionCheck(sendBytes, receiveBytes);


                // 3.2 如果通过,取出数据并转换为short[]
                List<byte> dataBytes = receiveBytes.GetRange(9, readCount - 9);

                short[] result = new short[count];
                for (int i = 0; i < count; i++)
                {
                    //BitConverter 只支持小端
                    List<byte> curBytes = dataBytes.GetRange(i * 2, 2);
                    // 第一种
                    //curBytes.Reverse();
                    //result[i] = BitConverter.ToInt16(curBytes.ToArray());
                    // 第二种
                    result[i] = BitConverter.ToInt16([curBytes[1], curBytes[0]]);

                }

                #endregion

                return result;
            }
        }
        #endregion

        #region 读取保持寄存器(int 32位) 功能码0x03 0x04
        /// <summary>
        /// 功能码0x03 0x04：读取保持寄存器(int 32位)
        /// </summary>
        /// <param name="funcCode">功能码。只支持0x03,0x04</param>
        /// <param name="startAddress">起始地址</param>
        /// <param name="count">要读的数字个数</param>
        /// <param name="endian">字节序,大小端模式,默认大端</param>
        /// <returns>数字数组</returns>
        public int[] ReadRegInt32(FuncCode funcCode, ushort startAddress, ushort count, Endian endian = Endian.BigEndian)
        {
            if (funcCode != FuncCode.ReadHoldingRegisters && funcCode != FuncCode.ReadInputRegisters)
            {
                throw new Exception("该方法只支持功能码0x03,0x04");
            }

            // 1.发送请求
            // 2.获取响应数据
            // 3.分析返回结果。返回int[]
            // 3.1 校验
            // 3.2 如果通过,取出数据并转换为int[]
            lock (lockObj)
            {
                #region 1.发送请求
                // 计算寄存器的数量(一个32位int占2个16位的寄存器),所以要*2
                ushort regCount = (ushort)(count * 2);

                // 发送的bytes
                List<byte> sendBytes = GetReadBytes(funcCode, startAddress, regCount);

                _socket.Send(sendBytes.ToArray());
                #endregion

                #region 2.获取响应数据
                // 报文返回的有9个字节是固定的即：读取的数字的个数 * 4(一个寄存器2个字节,32位数字占4个字节) + 9(固定字节)
                int readCount = count * 4 + 9; // 读取字节的个数

                List<byte> receiveBytes = GetReceiveBytes(readCount);

                #endregion

                #region 3.分析返回结果。返回int[]
                //3.1 校验
                ExceptionCheck(sendBytes, receiveBytes);

                // 3.2 如果通过,取出数据并转换为int[]
                List<byte> dataBytes = receiveBytes.GetRange(9, readCount - 9);

                int[] result = new int[count];
                for (int i = 0; i < count; i++)
                {
                    List<byte> curBytes = dataBytes.GetRange(i * 4, 4);
                    if (endian == Endian.BigEndian)  // 如果是大端则反转字节顺序
                    {
                        curBytes.Reverse();
                    }
                    //BitConverter 只支持小端
                    result[i] = BitConverter.ToInt32(curBytes.ToArray());
                }

                #endregion

                return result;
            }


        }
        #endregion

        #region 读取保持寄存器(32位 float) 功能码0x03 0x04
        /// <summary>
        /// 读取保持寄存器(32位 float) 功能码0x03 0x04
        /// </summary>
        /// <param name="funcCode">功能码。只支持0x03,0x04</param>
        /// <param name="startAddress">起始地址</param>
        /// <param name="count">要读的数字个数</param>
        /// <param name="endian">字节序,大小端模式,默认大端</param>
        /// <returns>数字数组</returns>
        public float[] ReadReg32Float(FuncCode funcCode, ushort startAddress, ushort count, Endian endian = Endian.BigEndian)
        {
            // 1.发送请求
            // 2.获取响应数据
            // 3.分析返回结果。返回float[]
            // 3.1 校验
            // 3.2 如果通过,取出数据并转换为float[]

            lock (lockObj)
            {
                #region 1.发送请求

                // 计算寄存器的数量(一个32位float占2个16位的寄存器),所以要*2
                ushort regCount = (ushort)(count * 2);
                // 发送的bytes
                List<byte> sendBytes = GetReadBytes(funcCode, startAddress, regCount);

                _socket.Send(sendBytes.ToArray());
                #endregion

                #region 2.获取响应数据
                // 报文返回的有9个字节是固定的即：读取的数字的个数 * 4(一个寄存器2个字节,32位数字占4个字节) + 9(固定字节)
                int readCount = count * 4 + 9; // 读取字节的个数

                List<byte> receiveBytes = GetReceiveBytes(readCount);

                #endregion

                #region 3.分析返回结果。返回float[]
                //3.1 校验
                ExceptionCheck(sendBytes, receiveBytes);

                // 3.2 如果通过,取出数据并转换为int[]
                List<byte> dataBytes = receiveBytes.GetRange(9, readCount - 9);

                float[] result = new float[count];
                for (int i = 0; i < count; i++)
                {
                    List<byte> curBytes = dataBytes.GetRange(i * 4, 4);
                    if (endian == Endian.BigEndian)  // 如果是大端则反转字节顺序
                    {
                        curBytes.Reverse();
                    }
                    //BitConverter 只支持小端
                    result[i] = BitConverter.ToSingle(curBytes.ToArray());
                }

                #endregion

                return result;
            }

        }
        #endregion

        #region 写单线圈 功能码0x05
        /// <summary>
        /// 写单线圈 (单个线圈的状态) 功能码0x05
        /// </summary>
        /// <param name="startAddress">起始地址</param>
        /// <param name="value">写的值</param>
        public void WriteSingleCoil(ushort startAddress, bool value)
        {
            // 1.发送请求
            // 2.获取响应数据
            // 3.校验
            lock (lockObj)
            {
                #region 1.发送请求
                // 写入的值bytes,如果是true则写入0xFF00,如果是false则写入0x0000
                byte[] writeValueBytes = value ? [0xFF, 0x00] : [0x00, 0x00];

                // 发送的bytes
                List<byte> sendBytes = GetSingleWriteBytes(FuncCode.WriteSingleCoil, startAddress, writeValueBytes);

                _socket.Send(sendBytes.ToArray());
                #endregion

                #region 2.获取响应数据
                // 接收字节的个数(因为写单线圈功能码0x05返回的报文是固定15个字节
                // 事务标识符(2B)、协议标识符(2B)、长度(2B)、单元标识符(1B)、功能码(1B)、起始地址(2B)、写入的值(2B))
                int readCount = 12;
                List<byte> receiveBytes = GetReceiveBytes(readCount);

                #endregion

                #region 3.校验
                ExceptionCheck(sendBytes, receiveBytes);
                #endregion
            }

        }
        #endregion

        #region 写多线圈 功能码0x0F
        /// <summary>
        /// 写多线圈  功能码0x0F
        /// </summary>
        /// <param name="startAddress">起始地址</param>
        /// <param name="values">写多个值</param>
        public void WriteMultipleCoil(ushort startAddress, bool[] values)
        {
            // 1.发送请求
            // 2.获取响应数据
            // 3.校验
            lock (lockObj)
            {
                #region 1.发送请求
                // 写入值的个数
                byte[] valueCountBytes = BitConverter.GetBytes(values.Length);

                // 写入的字节数
                //byte byteCount = (byte)Math.Ceiling(values.Length * 1.0 / 8);
                //byte byteCount = (byte)Math.Ceiling(values.Length / 8.0);
                byte byteCount = (byte)Math.Ceiling(values.Length / 8D);


                #region c# BitArray的实现(写入的值)
                //// 将bool[]转换为byte[]
                //// 从右向左填充字节(因为Modbus协议是从右向左填充的)
                ////[true, false, true, true]
                //// 0000 1101 <= 从右向左填充  0x0D
                ////[true,false,true,true,true]
                //// 0001 1101

                //BitArray bitArray = new BitArray(values);
                //byte[] writeBytes = new byte[byteCout];
                //bitArray.CopyTo(writeBytes, 0);
                #endregion

                #region 位运算实现(写入的值)
                //// 将bool[]转换为byte[]
                //// 从右向左填充字节(因为Modbus协议是从右向左填充的)
                ////[true, false, true, true]
                //// 0000 1101 <= 从右向左填充  0x0D
                ////[true,false,true,true,true]
                //// 0001 1101
                ////--------------------------------------------------
                //// 写入的值
                byte[] writeBytes = new byte[byteCount];
                for (int i = 0; i < values.Length; i++)
                {
                    // values[i] 判断当前线圈是否为 true（即是否要设置为 1）。
                    // 如果为 true，说明这个 bit 要设为 1。
                    // 如果为 false，不需要处理，因为数组初始化时默认是 0。
                    if (values[i])
                    {
                        // 确定当前 bit 应该写入哪个字节中。  索引 0~7 → 字节索引 0、索引 8~15 → 字节索引 1、索引 16~23 → 字节索引 2
                        int byteIndex = i / 8;
                        // 用 i % 8 得到当前 bit 在字节中的位置。 索引 0 → bit0、索引 1 → bit1、索引 7 → bit7....索引 8 → bit0（属于下一个字节）
                        int bitIndex = i % 8;
                        // 将当前 bit 设置为 1，并写入到对应的字节中。
                        /**
                         * (1 << bitIndex)：左移操作，构造一个只有对应 bit 为 1 的掩码。
                         *  例如：bitIndex = 3 → 1 << 3 = 8 → 二进制 0000 1000
                         *   =：按位或赋值，将当前字节中对应的 bit 设置为 1。
                         *  例如：当前字节是 0000 0000，与 0000 1000 按位或后变为 0000 1000
                         *   (byte)：确保结果是 byte 类型（防止溢出）
                         */
                        writeBytes[byteIndex] |= (byte)(1 << bitIndex);

                        //补充知识,如果你希望从左到右填充 bit（即索引 0 对应 bit7），可以修改为：
                        /**
                         * 这样：
                         *   索引 0 → bit7
                         *   索引 1 → bit6
                         *   ...
                         *   索引 7 → bit0
                         *   这在某些特定协议中可能会用到。
                         */
                        //writeBytes[byteIndex] |= (byte)(1 << (7 - (i % 8)));
                    }
                }
                #endregion

                // 发送的bytes
                List<byte> sendBytes = GetMultipleWriteBytes(FuncCode.WriteMultipleCoil, startAddress, valueCountBytes, byteCount, writeBytes);

                _socket.Send(sendBytes.ToArray());
                #endregion

                #region 2.获取响应数据
                int readCount = 12; // 读取(写多线圈 功能码0x0F 响应报文固定为12)字节的个数

                List<byte> receiveBytes = GetReceiveBytes(readCount);  // 返回的byte[]

                #endregion

                #region 3.校验
                ExceptionCheck(sendBytes, receiveBytes);
                #endregion
            }
        }
        #endregion

        #region 写单个寄存器 功能码0x06
        /// <summary>
        /// 写单个寄存器 功能码0x06
        /// </summary>
        /// <param name="startAddress">起始地址</param>
        /// <param name="value">写入的值</param>
        public void WriteSingleReg(ushort startAddress, short value)
        {
            // 1.发送请求
            // 2.获取响应数据
            // 3.校验
            lock (lockObj)
            {
                #region 1.发送请求

                // 写入的值
                byte[] valueBytes = BitConverter.GetBytes(value).Reverse().ToArray(); // 小端需要反转字节顺序

                // 发送的bytes
                List<byte> sendBytes = GetSingleWriteBytes(FuncCode.WriteSingleRegister, startAddress, valueBytes);

                _socket.Send(sendBytes.ToArray());
                #endregion

                #region 2.获取响应数据
                int readCount = 12; // 功能码0x06响应报文固定为12字节

                List<byte> reciveBytes = GetReceiveBytes(readCount);  // 返回的byte[]
                #endregion

                #region 3.校验
                ExceptionCheck(sendBytes, reciveBytes);
                #endregion
            }

        }
        #endregion

        #region 写多个寄存器(32位int,4个字节需要2个寄存器) 功能码0x10
        /// <summary>
        /// 写多个寄存器(32位int,4个字节需要2个寄存器) 功能码0x10
        /// </summary>
        /// <param name="startAddress">起始地址</param>
        /// <param name="values">写的多个值</param>
        /// <param name="endian">字节序(大小端)</param>
        public void WriteMultipleReg32Int(ushort startAddress, int[] values, Endian endian = Endian.BigEndian)
        {
            // 1.发送请求
            // 2.获取响应数据
            // 3.校验
            lock (lockObj)
            {
                #region 1.发送请求
                // 数量(寄存器的数量,一个32位int占2个16位的寄存器)
                byte[] regCountBytes = BitConverter.GetBytes((ushort)(values.Length * 2));

                // 写入值的byte数组
                List<byte> valuesBytes = new List<byte>();
                foreach (int i in values)
                {
                    byte[] curBytes = BitConverter.GetBytes(i); // 小端
                    if (endian == Endian.BigEndian)
                    {
                        curBytes = curBytes.Reverse().ToArray(); // 如果是大端则反转字节顺序
                    }

                    valuesBytes.AddRange(curBytes); // 添加写入的值
                }

                // 写入的字节数(因为一个寄存器2个字节,32位数字占4个字节，所以这里的字节数是values.Length * 4)
                byte byteCount = (byte)(values.Length * 4);

                // 发送的bytes
                List<byte> sendBytes = GetMultipleWriteBytes(FuncCode.WriteMultipleRegisters, startAddress, regCountBytes, byteCount, valuesBytes.ToArray());

                _socket.Send(sendBytes.ToArray());
                #endregion

                #region 2.获取响应数据
                int readCount = 12; // 功能码0x10响应报文固定为12字节 
                List<byte> reciveBytes = GetReceiveBytes(readCount);  // 返回的byte[]
                #endregion

                #region 3.校验
                ExceptionCheck(sendBytes, reciveBytes);
                #endregion
            }

        }
        #endregion

        #region 写多个寄存器(32位float,4个字节需要2个寄存器) 功能码0x10
        /// <summary>
        /// 写多个寄存器(32位float,4个字节需要2个寄存器) 功能码0x10
        /// </summary>
        /// <param name="startAddress">起始地址</param>
        /// <param name="values">写入的值</param>
        /// <param name="endian">字节序(大小端)</param>
        public void WriteMultipleReg32Float(ushort startAddress, float[] values, Endian endian = Endian.BigEndian)
        {
            // 1.发送请求
            // 2.获取响应数据
            // 3.校验
            lock (lockObj)
            {
                #region 1.发送请求
                // 数量(寄存器的数量,一个float占2个16位的寄存器,所以*2)
                byte[] regCountBytes = BitConverter.GetBytes((ushort)values.Length * (ushort)2);

                // 写入值的byte数组
                List<byte> valuesBytes = new List<byte>();

                foreach (float i in values)
                {
                    byte[] curBytes = BitConverter.GetBytes(i); // 小端
                    if (endian == Endian.BigEndian)
                    {
                        curBytes = curBytes.Reverse().ToArray(); // 如果是大端则反转字节顺序
                    }

                    valuesBytes.AddRange(curBytes); // 添加写入的值
                }

                // 写入的字节数(因为一个寄存器2个字节,32位数字占4个字节，所以这里的字节数是values.Length * 4)
                byte byteCount = (byte)(values.Length * 4);

                // 发送的bytes
                List<byte> sendBytes = GetMultipleWriteBytes(FuncCode.WriteMultipleRegisters, startAddress, regCountBytes, byteCount, valuesBytes.ToArray());

                _socket.Send(sendBytes.ToArray());
                #endregion

                #region 2.获取响应数据

                int readCount = 12; // 功能码0x10返回的报文是12个字节

                List<byte> receiveBytes = GetReceiveBytes(readCount);  // 返回的byte[]

                #endregion

                #region 3.校验
                ExceptionCheck(sendBytes, receiveBytes);
                #endregion
            }

        }
        #endregion

        #region 私有方法
        /// <summary>
        /// 事务标识符
        /// </summary>
        private ushort TransId = 0;
        /// <summary>
        /// 设置事务标识符
        /// </summary>
        private void SetTransId()
        {
            if (TransId == ushort.MaxValue)
            {
                TransId = 0;
            }
            else
            {
                TransId++;
            }
        }

        #region 请求读操作字节封装(适用于功能码0x01,0x02,0x03,0x04)
        /// <summary>
        /// 请求读操作字节封装
        /// </summary>
        /// <param name="funcCode"></param>
        /// <param name="startAddress"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        private List<byte> GetReadBytes(FuncCode funcCode, ushort startAddress, ushort count)
        {
            // 起始地址
            byte[] startBytes = BitConverter.GetBytes(startAddress);
            // 长度(读取数量)
            byte[] countBytes = BitConverter.GetBytes(count);

            SetTransId();  // 设置事务标识符
            byte[] transBytes = BitConverter.GetBytes(TransId);
            // 发送的bytes
            return [
                transBytes[1], // 事务标识符
                transBytes[0],
                0x00,0x00, // 协议标识符(固定为0x0000)
                0x00,0x06, // 长度(表示后续字节长度,固定为6个字节)
                0x01,// 单元标识符(固定,从站地址在TCP中没意义)
                (byte)funcCode,     // 功能码
                startBytes[1], // 起始地址高字节
                startBytes[0], // 起始地址低字节
                countBytes[1], // 读取长度高字节
                countBytes[0], // 读取长度低字节
            ];
        }
        #endregion

        #region 获取响应字节封装
        /// <summary>
        /// 获取读操作响应字节封装
        /// </summary>
        /// <param name="receiveCount">需要读取的字节数</param>
        /// <returns></returns>
        private List<byte> GetReceiveBytes(int receiveCount)
        {
            byte[] receiveBytes = new byte[receiveCount];
            try
            {
                _socket.Receive(receiveBytes); // 返回的byte[]
            }
            catch (Exception ex)
            {
                throw new Exception($"接收数据异常: {ex.Message}");
            }

            return receiveBytes.ToList();
        }
        #endregion

        #region 异常码
        /// <summary>
        /// 判断返回报文是否异常
        /// </summary>
        /// <param name="sendBytes">发送的报文</param>
        /// <param name="receiveBytes">响应的结果</param>
        /// <exception cref="Exception"></exception>
        private void ExceptionCheck(List<byte> sendBytes, List<byte> receiveBytes)
        {
            // 报文接收异常情况是将功能码的最高位设置成1了，所以功能码16进制是至少大于0x80，比如0x01功能码是0x81
            if (receiveBytes[7] > 0x80) // 出异常了(协议出错)
            {
                // 这里的receiveBytes[8]是错误码,可以根据错误码来判断是什么错误
                throw new Exception($"出异常了,异常信息{Common.ErrorCodes[receiveBytes[8]]}");
            }

            // 是否是同一次事务(判断事务标识符是否一致)
            if (!sendBytes.GetRange(0, 2).SequenceEqual(receiveBytes.GetRange(0, 2)))
            {
                throw new Exception($"发送和接收不是同一次事务");
            }
        }
        #endregion

        #region 单个写请求的报文 (适用于功能码0x05、0x06)    
        private List<byte> GetSingleWriteBytes(FuncCode funcCode, ushort startAddress, byte[] valuesBytes)
        {
            SetTransId();  // 设置事务标识符
            byte[] transBytes = BitConverter.GetBytes(TransId);
            // 起始地址
            byte[] startBytes = BitConverter.GetBytes(startAddress);

            // 发送的bytes
            List<byte> sendBytes = [
                transBytes[1], // 事务标识符
                transBytes[0],
                0x00,0x00, // 协议标识符(固定为0x0000)
                0x00,0x06, // 长度(表示后续字节长度,固定为6个字节)
                0x01,// 单元标识符(固定,从站地址在TCP中没意义)
                (byte)funcCode,     // 功能码
                startBytes[1],  // 起始地址
                startBytes[0],  // 起始地址
            ];

            sendBytes.AddRange(valuesBytes); // 写入的值

            return sendBytes;
        }
        #endregion

        #region 多个写请求的报文 (适用于功能码0x06、0x10)   
        /// <summary>
        /// 多个写请求的报文
        /// </summary>
        /// <param name="funcCode">功能码</param>
        /// <param name="startAddress">起始地址</param>
        /// <param name="valueCountBytes">写入数量</param>
        /// <param name="byteCount">字节数</param>
        /// <param name="valuesBytes">写入的值</param>
        /// <returns></returns>
        private List<byte> GetMultipleWriteBytes(FuncCode funcCode,
            ushort startAddress, byte[] valueCountBytes, byte byteCount, byte[] valuesBytes)
        {
            SetTransId();  // 设置事务标识符
            byte[] transBytes = BitConverter.GetBytes(TransId);

            // 起始地址
            byte[] startBytes = BitConverter.GetBytes(startAddress);

            // 长度(表示后续字节长度,固定为7 + 写入字节的长度)
            byte[] lenBytes = BitConverter.GetBytes((ushort)(7 + valuesBytes.Length));

            List<byte> sendBytes = [
                transBytes[1], // 事务标识符
                transBytes[0],
                0x00,0x00, // 协议标识符(固定为0x0000)
                lenBytes[1], // 长度(7 + 写入字节的长度)
                lenBytes[0],
                0x01,// 单元标识符(固定,从站地址在TCP中没意义)
                (byte)funcCode,     // 功能码
                startBytes[1], // 起始地址
                startBytes[0], // 起始地址
                valueCountBytes[1], // 写入的值个数
                valueCountBytes[0],  // 写入的值个数
                byteCount, // 写入的字节数
            ];

            // 写入的值
            sendBytes.AddRange(valuesBytes);

            return sendBytes;
        }
        #endregion

        #endregion

    }
}
